package com.hitcoder.chat.ui.widget

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.media.AudioManager
import android.media.AudioManager.OnAudioFocusChangeListener
import android.media.MediaRecorder
import android.os.Build
import android.os.Handler
import android.os.Message
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.widget.Toast
import androidx.appcompat.widget.AppCompatButton
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.hitcoder.chat.R
import com.hitcoder.chat.utils.DialogManager
import com.hitcoder.chat.utils.PRINT_STACK_TRACE
import com.hitcoder.chat.utils.PlayerManager
import java.io.File
import kotlin.math.roundToInt

/**
 * 自定义录音Button
 */
@Suppress("DEPRECATION", "unused")
class AudioRecorderButton @JvmOverloads constructor(
    private val myContext: Context,
    attrs: AttributeSet? = null
) : AppCompatButton(myContext, attrs) {

    companion object {
        // 按钮正常状态（默认状态）
        private const val STATE_NORMAL = 1

        //正在录音状态
        private const val STATE_RECORDING = 2

        //录音取消状态
        private const val STATE_CANCEL = 3

        //判断在Button上滑动距离，以判断 是否取消
        private const val DISTANCE_Y_CANCEL = 50

        //录音准备
        private const val MSG_AUDIO_PREPARED = 0x110

        //音量发生改变
        private const val MSG_VOICE_CHANGED = 0x111

        //取消提示对话框
        private const val MSG_DIALOG_DIMISS = 0x112

        //录音超时
        private const val MSG_VOICE_OVER = 0x113

        //还有10秒
        private const val MSG_VOICE_TEN_SECONDS = 0x114
    }

    //记录当前状态
    var currentState = STATE_NORMAL
        private set

    //是否开始录音标志
    private var recording = false

    //记录录音时间
    private var mTime = 0f

    // 是否触发longClick
    private var mReady = false

    //录音计时线程
    private var timer: Thread? = null

    //对话框管理工具类
    private var dialogManager: DialogManager? = null

    private var audioManager: AudioManager? = null

    private var finishRecorderCallBack: AudioFinishRecorderCallBack? = null

    //AudioRecord: 主要是实现边录边播（AudioRecord+AudioTrack）以及对音频的实时处理。
    // 优点：可以语音实时处理，可以实现各种音频的封装
    private var mMediaRecorder: MediaRecorder? = null

    //录音文件夹
    private var dir: File? = null

    //当前录音文件目录
    private var mCurrentFilePath: String? = null

    //是否准备好
    private var isPrepare = false

    fun init(dir: String) {
        this.dir = File(dir)
        dialogManager = DialogManager(myContext)
        audioManager = myContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager

        // 由于这个类是button所以在构造方法中添加监听事件
        setOnLongClickListener {
            mReady = true
            prepareAudio()
            false
        }
        setBackgroundResource(R.drawable.btn_recorder_normal)
        setText(R.string.str_recorder_normal)
    }

    /**
     * 获取音量大小的线程
     */
    private val mGetVoiceLevelRunnable = Runnable {
        while (recording) { //判断正在录音
            try {
                Thread.sleep(100)
                mTime += 0.1f //录音时间计算
                if (mTime < 60f && mTime > 50f) {
                    mHandler.sendEmptyMessage(MSG_VOICE_TEN_SECONDS) //录音剩余时间不到10秒
                } else if (mTime > 60f) {
                    mHandler.sendEmptyMessage(MSG_VOICE_OVER) //录音超时
                    recording = false
                } else {
                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGED) //每0.1秒发送消息
                }
            } catch (e: InterruptedException) {
                Log.i(PRINT_STACK_TRACE, "AudioRecorderButton run Exception " + e.message)
                Thread.currentThread().interrupt()
            }
        }
    }

    @SuppressLint("HandlerLeak")
    private val mHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_AUDIO_PREPARED -> {
                    if (PlayerManager.getManager(myContext).isPlaying) {
                        PlayerManager.getManager(myContext).stop()
                    }
                    audioManager?.requestAudioFocus(
                        audioFocusChangeListener,
                        AudioManager.STREAM_MUSIC,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
                    )
                    //显示对话框
                    dialogManager?.showRecordingDialog()
                    recording = true
                    // 开启一个线程计算录音时间
                    timer = Thread(mGetVoiceLevelRunnable)
                    timer?.start()
                    finishRecorderCallBack?.onStart()
                }
                MSG_VOICE_CHANGED ->                     //更新声音
                    dialogManager?.updateVoiceLevel(voiceLevel)
                MSG_DIALOG_DIMISS -> {
                    //取消对话框
                    dialogManager?.dismissDialog()
                    reset()
                    audioManager?.abandonAudioFocus(audioFocusChangeListener)
                    finishRecorderCallBack?.onCancel()
                }
                MSG_VOICE_OVER -> {
                    //如果状态为正在录音，则结束录制
                    dialogManager?.dismissDialog()
                    releaseMediaRecorder()
                    audioManager?.abandonAudioFocus(audioFocusChangeListener)
                    finishRecorderCallBack?.onFinish(mTime, mCurrentFilePath ?: "")
                    reset()
                }
                MSG_VOICE_TEN_SECONDS -> if (currentState == STATE_RECORDING) {
                    //更新声音
                    dialogManager?.updateVoiceLevel(voiceLevel)
                    dialogManager?.overTime((60 - mTime.roundToInt()).toString())
                }
            }
            super.handleMessage(msg)
        }
    }

    private val audioFocusChangeListener = OnAudioFocusChangeListener { focusChange: Int ->
        when (focusChange) {
            //重新获取焦点
            AudioManager.AUDIOFOCUS_GAIN -> {
            }
            //暂时失去焦点
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
            }
            //失去焦点
            AudioManager.AUDIOFOCUS_LOSS -> {
            }
        }
    }

    fun onHomeBack() {
        dialogManager?.dismissDialog()
        releaseMediaRecorder()
        reset()
    }

    fun setFinishRecorderCallBack(listener: AudioFinishRecorderCallBack) {
        finishRecorderCallBack = listener
    }

    fun over() {
        dialogManager?.dismissDialog()
        releaseMediaRecorder()
        audioManager?.abandonAudioFocus(audioFocusChangeListener)
        finishRecorderCallBack?.onFinish(mTime, mCurrentFilePath ?: "")
        reset()
    }

    /**
     * 处理Button的OnTouchEvent事件
     */
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        //获取TouchEvent状态
        val action = event.action
        // 获得x轴坐标
        val x = event.x.toInt()
        // 获得y轴坐标
        val y = event.y.toInt()
        when (action) {

            MotionEvent.ACTION_DOWN -> {
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
                    permissionForM()
                } else {
                    changeState(STATE_RECORDING)
                }
            }
            MotionEvent.ACTION_MOVE -> if (recording) {
                //根据x,y的坐标判断是否需要取消
                if (wantToCancel(x, y)) {
                    changeState(STATE_CANCEL)
                } else {
                    changeState(STATE_RECORDING)
                }
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                if (!mReady) {
                    audioManager?.abandonAudioFocus(audioFocusChangeListener)
                    reset()
                    return super.onTouchEvent(event)
                }
                if (!recording || mTime < 1.0f) { //如果时间少于1.0s，则提示录音过短
                    dialogManager?.tooShort()
                    cancelRecord()
                    // 延迟显示对话框
                    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000)
                    finishRecorderCallBack?.onCancel()
                } else if (currentState == STATE_RECORDING) {
                    //如果状态为正在录音，则结束录制
                    dialogManager?.dismissDialog()
                    releaseMediaRecorder()
                    finishRecorderCallBack?.onFinish(mTime, mCurrentFilePath ?: "")
                } else if (currentState == STATE_CANCEL) { // 想要取消
                    dialogManager?.dismissDialog()
                    cancelRecord()
                    finishRecorderCallBack?.onCancel()
                } else {
                    releaseMediaRecorder()
                    cancelRecord()
                }
                audioManager?.abandonAudioFocus(audioFocusChangeListener)
                reset()
            }
        }
        return super.onTouchEvent(event)
    }

    /**
     * 恢复状态及标志位
     */
    private fun reset() {
        recording = false
        mTime = 0f
        mReady = false
        timer?.apply {
            if (isAlive) interrupt()
        }
        changeState(STATE_NORMAL)
    }

    private fun wantToCancel(x: Int, y: Int): Boolean {
        // 超过按钮的宽度
        // 超过按钮的高度
        return if (x < 0 || x > width) true else y < -DISTANCE_Y_CANCEL || y > height + DISTANCE_Y_CANCEL
    }

    /**
     * 根据状态改变Button显示
     */
    private fun changeState(state: Int) {
        if (currentState != state) {
            currentState = state
            when (state) {
                STATE_NORMAL -> {
                    setBackgroundResource(R.drawable.btn_recorder_normal)
                    setText(R.string.str_recorder_normal)
                }
                STATE_RECORDING -> {
                    setBackgroundResource(R.drawable.btn_recorder_recording)
                    setText(R.string.str_recorder_recording)
                    if (recording) {
                        dialogManager?.recording()
                    }
                }
                STATE_CANCEL -> {
                    setBackgroundResource(R.drawable.btn_recorder_recording)
                    dialogManager?.wantToCancel()
                    setText(R.string.str_recorder_want_cancel)
                }
            }
        }
    }

    //录音操作
    private fun permissionForM() {
        if (ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.RECORD_AUDIO
            ) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                context as Activity,
                arrayOf(
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ),
                1
            )
            Toast.makeText(context, "请开启录音和读写文件相关权限", Toast.LENGTH_LONG).show()
        } else {

            //                        PlayerManager.getManager().raiseVolume();
            changeState(STATE_RECORDING)
        }
        //        changeState(STATE_RECORDING);
    }
    // 音频获取源
    //    public static int audioSource = MediaRecorder.AudioSource.MIC;
    //    // 设置音频采样率，44100是目前的标准，但是某些设备仍然支持22050，16000，11025
    //    public static int sampleRateInHz = 44100;
    //    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道，CHANNEL_CONFIGURATION_MONO为单声道
    //    public static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
    //    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
    //    public static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //    // 缓冲区字节大小
    //    public static int bufferSizeInBytes = 0;
    /**
     * 录音准备工作
     */
    private fun prepareAudio() {
        try {
            isPrepare = false
            dir?.let {
                if (!it.exists()) {
                    it.mkdirs() //文件不存在，则创建文件
                }
            }
            val file = File(dir, generateFileName())
            mCurrentFilePath = file.absolutePath
            mMediaRecorder = MediaRecorder().apply {
                // 设置输出文件路径
                setOutputFile(file.absolutePath)
                // 设置MediaRecorder的音频源为麦克风
                setAudioSource(MediaRecorder.AudioSource.MIC)
                // 设置音频格式为AMR_NB
                setOutputFormat(MediaRecorder.OutputFormat.AMR_NB)
                // 设置音频编码为AMR_NB
                setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
                //设置单声道
                setAudioChannels(1)
                //设置音频采样率
//            setAudioSamplingRate(8000);
                // 准备录音
                prepare()
                // 开始，必需在prepare()后调用
                start()
                // 准备完成
                isPrepare = true
                mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED)
            }
        } catch (e: Exception) {
            Log.i(PRINT_STACK_TRACE, "AudioMangerMy prepareAudio Exception " + e.message)
        }
    }

    /**
     * 根据时间戳随机生成录音文件名称
     */
    private fun generateFileName(): String {
        return System.currentTimeMillis().toString() + ".amr"
    }

    /**
     * 获取音量值
     */
    val voiceLevel: Int
        get() {
            if (isPrepare) {
                try {
                    //返回结果1-7之间
                    return if (mMediaRecorder == null) 1
                    // getMaxAmplitude返回的数值最大是32767
                    else 7 * mMediaRecorder!!.maxAmplitude / 32768 + 1
                } catch (e: Exception) {
                    Log.i(PRINT_STACK_TRACE, "AudioMangerMy getVoiceLevel Exception " + e.message)
                }
            }
            return 1
        }

    /**
     * 释放资源
     */
    fun releaseMediaRecorder() {
        try {
            mMediaRecorder?.stop()
            mMediaRecorder?.reset()
            mMediaRecorder = null
        } catch (e: Exception) {
//            Toast.makeText(MyApplication.getContext(),"请到手机设置中添加录音权限", Toast.LENGTH_LONG);
        }
    }

    /**
     * 录音取消
     */
    private fun cancelRecord() {
        releaseMediaRecorder()
        mCurrentFilePath?.let {
            //取消录音后删除对应文件
            val file = File(it)
            val result = file.delete()
            if (!result) Log.i("result", "delete file fail")
        }
        mCurrentFilePath = null
    }

    /**
     * 录音完成后的回调
     */
    interface AudioFinishRecorderCallBack {
        fun onFinish(seconds: Float, filePath: String)
        fun onStart()
        fun onCancel()
    }

}